using System;
using full_leaf_framework.Visual;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace touhou_bullet_rain;

public class Player {

    public Drawable selfDrawable;

    public string playerName;
    public string uuid;
    // 本地的实际坐标为pos，目标坐标为targetPos
    public Vector2 pos;
    private Vector2 posCorrectSwift;
    // 我认为处理延迟的一个办法应当是平滑坐标跳动过程
    private Vector2 prePos;
    public Vector2 velocity = Vector2.Zero;

    public int killCount = 0;
    public int deathCount = 0;

    public float moveStrength = 6500f;
    public float friction = 3000f;
    public float frictionRate = 10f;

    public bool keyWPressed = false;
    public bool keyAPressed = false;
    public bool keySPressed = false;
    public bool keyDPressed = false;

    public float grazeVelocity = 2400f;
    public float grazeColdDown = 0.8f;
    public float grazeMaxColdDown = 0.8f;

    public float angle = 0;

    public int score = 0;

    public float immuneTime = 0f;

    public float recovery = 0.0f;
    public float maxRecovery = 10.0f;

    public float hitPoints = 100;
    public Weapon weapon;

    private Level level;

    private float walkDustColdDown = 0f;
    private const float walkDustColdDownMax = 0.2f;

    public Player(string playerName, Vector2 pos, string uuid, Level level) {
        this.uuid = uuid;
        this.playerName = playerName;
        this.pos = pos;
        posCorrectSwift = Vector2.Zero;
        prePos = pos;
        this.level = level;
        var sprite = new AnimatedSprite(GameManager.Content.Load<Texture2D>("Player/player"), 1, 2);
        selfDrawable = new Drawable(sprite, pos, Vector2.Zero);
        weapon = new Weapon("normal_bullet");
    }

    public void HandleServerRequest(string[] paramsList) {
        if (!(paramsList[0] == uuid)) { return; }
        try {
            if (paramsList[1] == "pa") {
                posCorrectSwift = new Vector2(float.Parse(paramsList[2]),
                    float.Parse(paramsList[3])) - pos;
                angle = float.Parse(paramsList[4]);
            }
            else if (paramsList[1] == "h") {
                hitPoints = float.Parse(paramsList[2]);
            }
            else if (paramsList[1] == "r") {
                recovery = float.Parse(paramsList[2]);
            }
            else if (paramsList[1] == "s") {
                if (uuid == GameManager.uuid) {
                    string message = paramsList[3];
                    if (message.Substring(0, 5) == "Knock" && message != "Knock Down Youkai")
                        GameManager.belowBoardcast.Enqueue(message);
                }
                score = int.Parse(paramsList[2]);
            }
            else if (paramsList[1] == "w.b") {
                weapon.bulletType = paramsList[2];
            }
            else if (paramsList[1] == "w.a") {
                weapon.ammo = int.Parse(paramsList[2]);
            }
            else if (paramsList[1] == "w.m") {
                weapon.maxAmmo = int.Parse(paramsList[2]);
            }
            else if (paramsList[1] == "f") {
                weapon.bulletType = paramsList[2];
                weapon.ammo = int.Parse(paramsList[3]);
                weapon.maxAmmo = int.Parse(paramsList[4]);
            }
            else if (paramsList[1] == "kd") {
                killCount = int.Parse(paramsList[2]);
                deathCount = int.Parse(paramsList[3]);
            }
            else if (paramsList[1] == "i") {
                immuneTime = float.Parse(paramsList[2]);
            }
            else {
                throw new Exception("Wrong Format");
            }
        }
        catch (Exception e) {
            Console.WriteLine("Error When Handle Request -> " + e);
        }
    }

    public void Update(GameTime gameTime) {
        selfDrawable.pos = pos;
        selfDrawable.angle = angle;
        if (hitPoints >= float.Epsilon) { selfDrawable.currentAnimation.CurrentFrame = 0; }
        else { selfDrawable.currentAnimation.CurrentFrame = 1; }
        immuneTime -= (float)gameTime.ElapsedGameTime.TotalSeconds;
        if (immuneTime < float.Epsilon) { immuneTime = 0.0f; }
        recovery -= (float)gameTime.ElapsedGameTime.TotalSeconds;
        if (recovery < float.Epsilon) { recovery = 0.0f; }
        // 处理本地更新事务
        grazeColdDown -= (float)gameTime.ElapsedGameTime.TotalSeconds;
        Vector2 moveDirection = new Vector2(0, 0);
        moveDirection.Y -= keyWPressed ? 1 : 0;
        moveDirection.Y += keySPressed ? 1 : 0;
        moveDirection.X -= keyAPressed ? 1 : 0;
        moveDirection.X += keyDPressed ? 1 : 0;
        if (moveDirection.Length() > float.Epsilon && hitPoints >= float.Epsilon) {
            moveDirection.Normalize();
            moveDirection *= (moveStrength - friction) / frictionRate *
                (float)gameTime.ElapsedGameTime.TotalSeconds;
            pos += moveDirection;
        }
        CorrectCurrPos(gameTime);
        // 让当前坐标插值接近目标坐标（强制拉近）
        velocity = (pos - prePos) * (float)gameTime.ElapsedGameTime.TotalSeconds;
        prePos = pos;
        // 处理本地的玩家坐标改变
        walkDustColdDown -= (float)gameTime.ElapsedGameTime.TotalSeconds;
        if (walkDustColdDown < float.Epsilon) { walkDustColdDown = 0.0f; }
        if (velocity.Length() > 1f && walkDustColdDown < float.Epsilon) {
            float walkAngle = VectorToAngle(-velocity);
            level.particleController.Burst("walk_burst", pos, angleRange: new float[2]
            { walkAngle - MathF.PI / 24, walkAngle + MathF.PI / 24});
            walkDustColdDown = walkDustColdDownMax;
        }
        // 走动粒子效果
    }

    private void CorrectCurrPos(GameTime gameTime) {
        // 平滑插值使得对象移动同步偏差量
        float distance = posCorrectSwift.Length();
        float approachVelocity = 30f + distance * 1.5f + distance * distance * 0.5f;
        approachVelocity *= (float)gameTime.ElapsedGameTime.TotalSeconds;
        if (distance <= approachVelocity) {
            pos += posCorrectSwift;
            posCorrectSwift = Vector2.Zero;
        }
        else {
            Vector2 currSwift = posCorrectSwift;
            currSwift.Normalize(); currSwift *= approachVelocity;
            pos += currSwift;
            posCorrectSwift -= currSwift;
        }
    }

    public void HandleBurstRequest(string[] burstArgus) {
        if (burstArgus[1] == "graze_burst") {
            level.particleController.Burst("walk_burst", pos, angleRange: new float[2]
            { 0, 2 * MathF.PI }, particleCount: 16,
            velocityRange: new float[2] { 20f, 350f });
        }
        else {
            level.particleController.Burst(burstArgus[1], pos);
        }
    }

    public void Draw(Camera camera) {
        if (selfDrawable is not null) {
            selfDrawable.transparency = hitPoints >= float.Epsilon ? 1f : 0.5f;
            camera.insertObject(selfDrawable);
            GameManager.fontController.InsertDrawObjects(camera, playerName, pos - new Vector2(0, 25),
            BmfontDrawable.TranslateMethod.Middle, 0.5f / camera.scale);
        }
    }

    public static float VectorToAngle(Vector2 direction) {
        float angle = MathF.Atan2(direction.Y, direction.X);
        if (angle < 0) { angle += 2 * MathF.PI; }
        return angle;
    }

}